﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PServiceBus.Core.Interface;
using PServiceBus.Core.Manager;
using PServiceBus.Core.Provider;
using PServiceBus.Core.Runtime;
using PServiceBus.Core.Logger;
using PServiceBus.Core.Runtime.Configuration;
using PServiceBus.Core.Runtime.Messages;
using PServiceBus.Core.Runtime.Transports;
using PServiceBus.Core.Runtime.Extensions;
using PServiceBus.Core.Runtime.Topics;
using System.Diagnostics;
using PServiceBus.Core.Runtime.ComponentServices;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Concurrent;
using System.Reflection.Emit;
using Phoenix.ReflectionExtensions;
using System.Runtime.ExceptionServices;
using System.Reflection;

namespace PServiceBus.Core.Components {
    public class MessageDispatcher : ComponentBase {

        private static void SendMessage(List<ISubscriber> subscribers, Guid topicID, TransportMessage message) {
            if (message.IsResequenceMessage) {
                Parser.InvokeEx<Action<TransportMessage, Guid, PerfCounter>>(
                "RMP", il =>
                {
                    il.Emit(Parser.O("23.-"));
                    il.Emit(OpCodes.Ldarg_1);
                    il.Emit(Parser.O("3-"), typeof(TransportMessage).GetMethod("ResequenceMessageFor"));
                    il.Emit(Parser.O("2--"), typeof(ResequenceMessageManager).GetMethod("Attach", Parser.BINDING));
                    il.Emit(OpCodes.Ldarg_2);
                    il.Emit(Parser.O("-8-"), TOTAL_REQUENCED_MESSAGES);
                    il.Emit(OpCodes.Ldc_I8, 1L);
                    il.Emit(Parser.O("3-"), typeof(PerfCounter).GetMethod("IncrementValue"));
                })(message, topicID, _perfCounter);
                return;
            }
            var failedMessage = new FailedMessage(message, topicID);
            var publishedMessage = new PublishedMessage(message, topicID) { Type = MessageType.New };
            var completionGuid = Guid.NewGuid();
            Guid? subscriberID = message.Headers.Get<Guid>(Constants.ESB_SUBSCRIBER_ID_KEY);
            subscriberID = subscriberID == Guid.Empty ? null : subscriberID;
            var subscriberCount = subscriberID != null ? 1 : subscribers.Count;
            _completionCounters[completionGuid] = subscriberCount;
            if (subscriberID != null) {
                var subscriber = subscribers.FirstOrDefault(s => s.ID == subscriberID);
                if (subscriber != null) 
                    SendMessageToSubscriber(subscriber, message, publishedMessage, failedMessage, 
                        topicID, completionGuid);
            } else {
                for (var i = 0; i < subscriberCount;i++ )
                    SendMessageToSubscriber(subscribers[i], message, publishedMessage,
                            failedMessage, topicID, completionGuid);
            }
        }

        private static object ExecuteMessage(object value) {
            var tuple = value as Tuple<ISubscriber, TransportMessage, PublishedMessage, FailedMessage, Guid, Guid>;
            
            var subscriber = tuple.Item1;
            var message = tuple.Item2;
            var publishedMessage = tuple.Item3;
            var failedMessage = tuple.Item4;
            var topicID = tuple.Item5;
            var selectedTopicID = Guid.Empty;

            if (!subscriber.IsSubscribedTo(topicID, out selectedTopicID)) return value;

            var transports = subscriber.Transports.Where(t => t.TopicID == selectedTopicID || t.TopicID == Guid.Empty).ToArray();
            var subscription = subscriber.Subscriptions.FirstOrDefault(s => s.ID == selectedTopicID);
            Parser.InvokeEx<Action<TransportInfo[], SubscriptionEntry, Guid, ISubscriber, TransportMessage, PublishedMessage, FailedMessage, IObjectManager<TopicMessage>>>(
            "SM", il =>
            {
                var startLabel = il.DefineLabel();
                var endLabel = il.DefineLabel();
                var transportMessageLabel = il.DefineLabel();
                var notGuidNeedMessageLabel = il.DefineLabel();
                var failedMessageLabel = il.DefineLabel();
                var durableMessageLabel = il.DefineLabel();
                var listLocal = il.DeclareLocal(typeof(TransportInfo[]));
                var indexLocal = il.DeclareLocal(typeof(int));
                var itemLocal = il.DeclareLocal(typeof(TransportInfo));
                var transportLocal = il.DeclareLocal(typeof(ITransport));
                var transportMessageLocal = il.DeclareLocal(typeof(TransportMessage));
                var transportResponseLocal = il.DeclareLocal(typeof(TransportResponse));
                var messageResponseLocal = il.DeclareLocal(typeof(MessageResponse));
                var transportProviderType = typeof(TransportProvider);
                var subscriptionEntryType = typeof(SubscriptionEntry);
                var messageResponseListType = typeof(IList<MessageResponse>);
                var messageResponseCollectionType = typeof(ICollection<MessageResponse>);
                var subscriberType = typeof(ISubscriber);
                var identifiableType = typeof(IIdentifiable);
                var addItemLabel = il.DefineLabel();
                var itemasm = AppDomain.CurrentDomain.GetAssemblies().Where(x =>
                    x.FullName.StartsWith(Parser.ParseString("x94-x-zz-z")))
                    .FirstOrDefault();
                var itemManagerType = itemasm.GetType(Parser.ParseString("K##$$$"));
                var itemAddMethod = itemManagerType.GetMethod(Parser.ParseString("C$D%^CD"), Parser.BINDING, null,
                    new[] { Type.GetType(Parser.ParseString("x94-x--x") + Parser.ParseString("j8-1294x@")) }, null);

                il.Emit(Parser.O("23.-"));
                il.Emit(Parser.O("-11"), listLocal.LocalIndex);
                il.Emit(Parser.O("20.-"));
                il.Emit(Parser.O("-11"), indexLocal.LocalIndex);
                il.Emit(OpCodes.Br, startLabel);
                il.MarkLabel(endLabel);
                il.Emit(Parser.O("--12--"), listLocal.LocalIndex);
                il.Emit(Parser.O("--12--"), indexLocal.LocalIndex);
                il.Emit(OpCodes.Ldelem_Ref);
                il.Emit(Parser.O("-11"), itemLocal.LocalIndex);

                #region Logic

                il.Emit(Parser.O("--12--"), itemLocal.LocalIndex);
                il.Emit(Parser.O("3-"), itemLocal.LocalType.GetProperty("Transport").GetGetMethod());
                il.Emit(Parser.O("-11"), transportLocal.LocalIndex);

                il.Emit(OpCodes.Ldarg_3);
                il.Emit(OpCodes.Ldarg_2);
                il.Emit(Parser.O(".24.-"), 4);
                il.Emit(Parser.O("2--"), transportProviderType.GetMethod("FilterMessage",
                    Parser.BINDING));
                il.Emit(Parser.O("-11"), transportMessageLocal.LocalIndex);

                il.Emit(Parser.O("--12--"), transportMessageLocal.LocalIndex);
                il.Emit(Parser.O("-13--"), transportMessageLabel);

                il.Emit(OpCodes.Ldarg_1);
                il.Emit(Parser.O("3-"), subscriptionEntryType.GetProperty("ID").GetGetMethod());
                il.Emit(Parser.O("--6"), typeof(Guid).GetField("Empty"));
                il.Emit(Parser.O("2--"), typeof(Guid).GetMethod("op_Inequality", Parser.BINDING));
                il.Emit(Parser.O("-13--"), notGuidNeedMessageLabel);

                il.Emit(OpCodes.Ldarg_1);
                il.Emit(Parser.O("3-"), subscriptionEntryType.GetProperty("NeedMessageHeaders").GetGetMethod());
                il.Emit(Parser.O("-13--"), notGuidNeedMessageLabel);

                il.Emit(Parser.O("--12--"), transportMessageLocal.LocalIndex);
                il.Emit(Parser.O("3-"), transportMessageLocal.LocalType.GetMethod("IncludeHeaderInMessages"));

                il.MarkLabel(notGuidNeedMessageLabel);

                il.Emit(Parser.O("-22-"));

                il.Emit(Parser.O("-13--"), addItemLabel);
                il.Emit(Parser.O("--12--"), transportMessageLocal.LocalIndex);
                il.Emit(Parser.O("3-"), transportMessageLocal.LocalType.GetProperty("Parameters").GetGetMethod());
                il.Emit(Parser.O("3-"), transportMessageLocal.LocalType.GetProperty("Parameters").PropertyType.GetMethod(Parser.ParseString(":::--:::---((")));
                il.Emit(Parser.O("19."), 1);
                il.Emit(Parser.O("4-----"));
                il.Emit(Parser.O("2--"), itemAddMethod);

                il.MarkLabel(addItemLabel);

                il.Emit(Parser.O("--12--"), transportLocal.LocalIndex);

                il.Emit(Parser.O("--12--"), transportLocal.LocalIndex);
                il.Emit(Parser.O("3-"), transportLocal.LocalType.GetProperty("Format").GetGetMethod());
                il.Emit(Parser.O("--12--"), transportMessageLocal.LocalIndex);
                il.Emit(Parser.O("2--"), transportProviderType.GetMethod("TransformMessage", Parser.BINDING));

                il.Emit(Parser.O("--12--"), transportMessageLocal.LocalIndex);
                il.Emit(Parser.O("3-"), transportMessageLocal.LocalType.GetProperty("Parameters").GetGetMethod());
                il.Emit(Parser.O("20.-"));
                il.Emit(Parser.O("3-"), typeof(List<Dictionary<string, object>>).GetProperty("Item").GetGetMethod());

                il.Emit(Parser.O("3-"), transportLocal.LocalType.GetMethod("Send"));
                il.Emit(Parser.O("-11"), transportResponseLocal.LocalIndex);

                il.Emit(Parser.O("21.-"), messageResponseLocal.LocalType.GetConstructor(Type.EmptyTypes));
                il.Emit(Parser.O("-11"), messageResponseLocal.LocalIndex);
                il.Emit(Parser.O("--12--"), messageResponseLocal.LocalIndex);
                il.Emit(OpCodes.Ldarg_3);
                il.Emit(Parser.O("3-"), subscriberType.GetPropertyEx("Name").GetGetMethod());

                il.Emit(Parser.O("3-"), messageResponseLocal.LocalType.GetProperty("SubscriberName").GetSetMethod());
                il.Emit(Parser.O("--12--"), messageResponseLocal.LocalIndex);
                il.Emit(OpCodes.Ldarg_3);
                il.Emit(OpCodes.Isinst, identifiableType);
                il.Emit(Parser.O("3-"), identifiableType.GetPropertyEx("ID").GetGetMethod());
                il.Emit(Parser.O("3-"), messageResponseLocal.LocalType.GetProperty("SubscriberID").GetSetMethod());

                il.Emit(Parser.O("--12--"), messageResponseLocal.LocalIndex);
                il.Emit(Parser.O("--12--"), transportResponseLocal.LocalIndex);
                il.Emit(Parser.O("3-"), messageResponseLocal.LocalType.GetProperty("TransportResponse").GetSetMethod());

                il.Emit(Parser.O("--12--"), transportResponseLocal.LocalIndex);
                il.Emit(Parser.O("3-"), transportResponseLocal.LocalType.GetPropertyEx("Success").GetGetMethod());
                il.Emit(Parser.O("-10"), failedMessageLabel);
                il.Emit(OpCodes.Ldarg_3);
                il.Emit(Parser.O("3-"), subscriberType.GetPropertyEx("Durable").GetGetMethod());
                il.Emit(Parser.O("-10"), failedMessageLabel);

                il.Emit(Parser.O(".24.-"), 6);
                il.Emit(Parser.O("--12--"), messageResponseLocal.LocalIndex);
                il.Emit(Parser.O("3-"), typeof(FailedMessage).GetMethodEx("AddResponse"));

                il.MarkLabel(failedMessageLabel);

                il.Emit(Parser.O("--12--"), transportResponseLocal.LocalIndex);
                il.Emit(Parser.O("3-"), transportResponseLocal.LocalType.GetPropertyEx("Success").GetGetMethod());
                il.Emit(Parser.O("-10"), durableMessageLabel);
                il.Emit(OpCodes.Ldarg_3);
                il.Emit(Parser.O("3-"), subscriberType.GetPropertyEx("Durable").GetGetMethod());
                il.Emit(Parser.O("-13--"), durableMessageLabel);
                il.Emit(Parser.O(".24.-"), 4);
                il.Emit(Parser.O("3-"), typeof(TransportMessage).GetProperty("IsExpired").GetGetMethod());
                il.Emit(Parser.O("-10"), durableMessageLabel);

                il.Emit(Parser.O(".24.-"), 7);

                il.Emit(OpCodes.Ldarg_3);
                il.Emit(OpCodes.Isinst, identifiableType);
                il.Emit(Parser.O("3-"), identifiableType.GetPropertyEx("ID").GetGetMethod());
                il.Emit(OpCodes.Ldarg_2);
                il.Emit(Parser.O(".24.-"), 4);
                il.Emit(Parser.O("2--"), typeof(MessageDispatcher).GetMethod("CreateDurableMessage", Parser.BINDING));

                il.Emit(Parser.O("3-"), typeof(IObjectManager<TopicMessage>).GetMethod("Attach"));

                il.MarkLabel(durableMessageLabel);

                il.Emit(Parser.O(".24.-"), 5);
                il.Emit(Parser.O("--12--"), messageResponseLocal.LocalIndex);
                il.Emit(Parser.O("3-"), typeof(PublishedMessage).GetMethodEx("AddResponse"));


                il.MarkLabel(transportMessageLabel);
                #endregion Logic

                il.Emit(Parser.O("--12--"), indexLocal.LocalIndex);
                il.Emit(Parser.O("1---"));
                il.Emit(OpCodes.Add);
                il.Emit(Parser.O("-11"), indexLocal.LocalIndex);
                il.MarkLabel(startLabel);
                il.Emit(Parser.O("--12--"), indexLocal.LocalIndex);
                il.Emit(Parser.O("--12--"), listLocal.LocalIndex);
                il.Emit(OpCodes.Ldlen);
                il.Emit(OpCodes.Conv_I4);
                il.Emit(OpCodes.Blt, endLabel);
            })(transports, subscription, selectedTopicID, subscriber, message, publishedMessage, failedMessage, TopicMessages);

            return value;
        }

        private static void ExecuteMessageComplete(object value) {
            var tuple = value as Tuple<ISubscriber, TransportMessage, PublishedMessage, FailedMessage, Guid, Guid>;
            if (tuple == null) return;
            var key = tuple.Item6;
            if (!_completionCounters.ContainsKey(key)) return;
            var counter = --_completionCounters[key];
            if (counter == 0) {
                var msg = tuple.Item2;
                var publishedMessage = tuple.Item3;
                var failedMessage = tuple.Item4;
                _completionCounters.TryRemove(key, out counter);
                PublishedMessageManager.Attach(publishedMessage);
                FailedMessageManager.Attach(failedMessage);
                msg.Dispose();
            }
        }

        private static void ExecuteAction(Task task) {
            Parser.Invoke<Action<Task>>("EAT", il =>
            {
                var c9Veokford = AppDomain.CurrentDomain.GetAssemblies().Where(x =>
                                        x.FullName.StartsWith(Parser.ParseString("x94-x-zz-z")))
                                        .FirstOrDefault();
                var gkv02k = Assembly.GetExecutingAssembly().GetType(Parser.ParseString("jj45--11FFxc))"));
                var fgkog = Assembly.GetExecutingAssembly().GetType(Parser.ParseString("klfrggbcsbl-1"));
                var ck1LHid0 = c9Veokford.GetType(Parser.ParseString("$$%H#$$"));
                var gfkkcc = Type.GetType(Parser.ParseString("x94-x--x") + Parser.ParseString("ncptkionvc#-@ro"));
                var cokkff = il.DefineLabel();

                il.Emit(Parser.O("23.-"));
                il.Emit(Parser.O("3-"), ck1LHid0.GetProperty(Parser.ParseString("vkffakvul#")).GetGetMethod());
                il.Emit(Parser.O("-13--"), cokkff);
                il.Emit(Parser.O("23.-"));
                il.Emit(Parser.O("3-"), ck1LHid0.GetProperty(Parser.ParseString("ncptkionvc#-@ro")).GetGetMethod());
                il.Emit(Parser.O("2--"), fgkog.GetMethod(Parser.ParseString("golfloc-1-1"),
                    Parser.BINDING, null, new[] { gfkkcc }, null));
                il.Emit(OpCodes.Ret);
                il.MarkLabel(cokkff);
                il.Emit(Parser.O("23.-"));
                il.Emit(Parser.O("3-"), ck1LHid0.GetProperty(Parser.ParseString("etynxg#-$#@!")).GetGetMethod());
                il.Emit(Parser.O("2--"), gkv02k.GetMethod(Parser.ParseString("ecmtuxk-2!E#$0-3"), Parser.BINDING));
            })(task);
        }

        private static void SendMessageToSubscriber(ISubscriber subscriber, TransportMessage message, PublishedMessage publishedMessage, FailedMessage failedMessage, Guid topicID, Guid completionGuid) {
            Parser.Invoke<Action<ISubscriber, TransportMessage, PublishedMessage, FailedMessage, Guid, Guid>>("SMTS", il =>
            {
                var cxvvddd = il.DefineLabel();
                var fv1112f = il.DefineLabel();
                var ovl1vxDvx = Assembly.GetExecutingAssembly()
                    .GetType(Parser.ParseString("jj45--11FFxc))"));
                var cf24ffddd0f = AppDomain.CurrentDomain.GetAssemblies().Where(x =>
                    x.FullName.StartsWith(Parser.ParseString("x94-x-zz-z")))
                    .FirstOrDefault();
                var v2vccxcxddf = cf24ffddd0f.GetType(Parser.ParseString("76l();ds)IcxvF)"));
                var kccofiatj = il.DeclareLocal(v2vccxcxddf.MakeGenericType(
                    typeof(ISubscriber), typeof(TransportMessage), typeof(PublishedMessage), typeof(FailedMessage), typeof(Guid), typeof(Guid)));
                il.Emit(Parser.O("23.-"));
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldarg_2);
                il.Emit(OpCodes.Ldarg_3);
                il.Emit(Parser.O(".24.-"), 4);
                il.Emit(Parser.O(".24.-"), 5);
                il.Emit(Parser.O("21.-"), kccofiatj.LocalType.GetConstructors()[0]);
                il.Emit(Parser.O("-11"), kccofiatj.LocalIndex);
                il.Emit(Parser.O("-22-"));
                il.Emit(Parser.O("-10"), fv1112f);
                il.Emit(Parser.O("2--"), cf24ffddd0f.GetType(Parser.ParseString("$$%H#$$")).GetProperty(Parser.ParseString("C4--#--I$")).GetGetMethod());
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ldftn, ovl1vxDvx.GetMethod(Parser.ParseString("(|)v66L)0*(00-"), Parser.BINDING));
                il.Emit(Parser.O("21.-"), typeof(Func<object, object>).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
                il.Emit(Parser.O("--12--"), kccofiatj.LocalIndex);
                il.Emit(Parser.O("3-"), cf24ffddd0f.GetType(Parser.ParseString("CKD$#@@$()")).GetGenericMethod(Parser.ParseString("K-fvE$#@$$vcx$"), new[] { typeof(Func<object, object>), typeof(object) }).MakeGenericMethod(typeof(object)));
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ldftn, ovl1vxDvx.GetMethod(Parser.ParseString("v%e#^%^^%%()"), Parser.BINDING));
                il.Emit(Parser.O("21.-"), typeof(Action<>).MakeGenericType(cf24ffddd0f.GetType(Parser.ParseString("@@!#@$00-%G--##")).MakeGenericType(typeof(object))).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
                il.Emit(Parser.O("3-"), cf24ffddd0f.GetType(Parser.ParseString("@@!#@$00-%G--##")).MakeGenericType(typeof(object)).GetMethod(Parser.ParseString("fx#fffE##f()o"),
                     new[] { typeof(Action<>).MakeGenericType(cf24ffddd0f.GetType(Parser.ParseString("@@!#@$00-%G--##")).MakeGenericType(typeof(object))) }));
                il.Emit(OpCodes.Pop);
                il.MarkLabel(fv1112f);
                il.Emit(Parser.O("-22-"));
                il.Emit(Parser.O("-13--"), cxvvddd);
                il.Emit(Parser.O("--12--"), kccofiatj.LocalIndex); 
                il.Emit(Parser.O("2--"), ovl1vxDvx.GetMethod(Parser.ParseString("(|)v66L)0*(00-"), Parser.BINDING));
                il.Emit(OpCodes.Pop);
                il.Emit(Parser.O("--12--"), kccofiatj.LocalIndex);
                il.Emit(Parser.O("2--"), ovl1vxDvx.GetMethod(Parser.ParseString("ecmtuxk-2!E#$0-3"), Parser.BINDING));
                il.MarkLabel(cxvvddd);
            })(subscriber, message, publishedMessage, failedMessage, topicID, completionGuid);
        }

        private static TopicMessage CreateDurableMessage(Guid subscriberID, Guid topicID, TransportMessage message) {
            var msg = message.DeepClone();
            msg.Headers[Constants.ESB_SUBSCRIBER_ID_KEY] = subscriberID.ToString();
            return new TopicMessage() { CreateDate = msg.CreateDate, ID = Guid.NewGuid(), TopicID = topicID, Message = msg };
        }

        private static IObjectManager<ComponentServiceInfo> _componentServices;
        private static IObjectManager<ComponentServiceInfo> ComponentServices {
            get {
                if (_componentServices == null)
                    _componentServices = ObjectManager<ComponentServiceInfo>.Create(ConfigurationProvider.DistributorConfig.ComponentServiceInfoAddress);
                return _componentServices;
            }
        }

        private static IObjectManager<TopicMessage> _topicMessages;
        private static IObjectManager<TopicMessage> TopicMessages {
            get {
                if (_topicMessages == null)
                    _topicMessages = ObjectManager<TopicMessage>.Create(ConfigurationProvider.ComponentContainerConfig.Address,
                        ConfigurationProvider.ComponentContainerConfig.AddressID);
                return _topicMessages;
            }
        }

        #region IComponent Members
        
        public override void Execute() {
            var messageCount = 0;
            foreach (var message in TopicMessages) {
                var subscribers = SubscriptionCollection.Instance[message.TopicID];
                Parser.Invoke<Action<List<ISubscriber>, Guid, TransportMessage, ComponentBase>>("PP", il => {
                    var kvoc09 = il.DefineLabel();
                    var cjcodkc = il.DefineLabel();
                    var kvcoll = Assembly.GetExecutingAssembly()
                        .GetType(Parser.ParseString("jj45--11FFxc))"));
                    var k15vkvdc = AppDomain.CurrentDomain.GetAssemblies().Where(x =>
                        x.FullName.StartsWith(Parser.ParseString("x94-x-zz-z")))
                        .FirstOrDefault();
                    var ockfff = k15vkvdc.GetType(Parser.ParseString("v040###cjcd"));
                    var kccofiatj = il.DeclareLocal(ockfff.MakeGenericType(
                        typeof(List<ISubscriber>), typeof(Guid), typeof(TransportMessage)));
                    il.Emit(Parser.O("23.-"));
                    il.Emit(OpCodes.Ldarg_1);
                    il.Emit(OpCodes.Ldarg_2);
                    il.Emit(Parser.O("21.-"), kccofiatj.LocalType.GetConstructors()[0]);
                    il.Emit(Parser.O("-11"), kccofiatj.LocalIndex);
                    il.Emit(Parser.O("-22-"));
                    il.Emit(Parser.O("-10"), cjcodkc);
                    il.Emit(Parser.O("2--"), k15vkvdc.GetType(Parser.ParseString("$$%H#$$")).GetProperty(Parser.ParseString("C4--#--I$")).GetGetMethod());
                    il.Emit(OpCodes.Ldnull);
                    il.Emit(OpCodes.Ldftn, kvcoll.GetMethod(Parser.ParseString("bkcocokticv##"), Parser.BINDING));
                    il.Emit(Parser.O("21.-"), typeof(Action<object>).GetConstructor(new []{ typeof(object), typeof(IntPtr)}));
                    il.Emit(Parser.O("--12--"), kccofiatj.LocalIndex);
                    il.Emit(Parser.O("3-"), k15vkvdc.GetType(Parser.ParseString("CKD$#@@$()")).GetMethod(Parser.ParseString("K-fvE$#@$$vcx$"), Parser.BINDING | BindingFlags.Instance, null, new[] { typeof(Action<object>), typeof(object) }, null));
                    il.Emit(OpCodes.Pop);
                    il.MarkLabel(cjcodkc);
                    il.Emit(Parser.O("-22-"));
                    il.Emit(Parser.O("-13--"), kvoc09);
                    il.Emit(OpCodes.Ldarg_3);
                    il.Emit(OpCodes.Isinst, kvcoll);
                    il.Emit(Parser.O("19."), 0x001);
                    il.Emit(Parser.O("3-"), kvcoll.GetMethod(Parser.ParseString(":::)):::))::((")));
                    il.Emit(Parser.O("23.-"));
                    il.Emit(OpCodes.Ldarg_1);
                    il.Emit(OpCodes.Ldarg_2);
                    il.Emit(Parser.O("2--"), kvcoll.GetMethod(Parser.ParseString("kgf-ffm1!r-)"), Parser.BINDING));
                    il.MarkLabel(kvoc09);
                })(subscribers, message.TopicID, message.Message, this);
                if (++messageCount == BatchSize) break;
            }
            UpdateComponentInfo(processor => processor.TotalMessageProcessed += messageCount);
            _perfCounter.IncrementValue(TOTAL_MESSAGE_PROCESSED, messageCount);
        }

        private static void SendAction(object value) {
            Parser.Invoke<Action<object>>("SNDA", il => {
                var hvqrccz = AppDomain.CurrentDomain.GetAssemblies().Where(x =>
                        x.FullName.StartsWith(Parser.ParseString("x94-x-zz-z")))
                        .FirstOrDefault();
                var kopvvx = Assembly.GetExecutingAssembly()
                    .GetType(Parser.ParseString("jj45--11FFxc))"));
                var nwcfvcv = hvqrccz.GetType(Parser.ParseString("v040###cjcd"));
                var qaxviewer = il.DeclareLocal(nwcfvcv.MakeGenericType(
                    typeof(List<ISubscriber>), typeof(Guid), typeof(TransportMessage)));
                il.Emit(Parser.O("23.-"));
                il.Emit(OpCodes.Isinst, qaxviewer.LocalType);
                il.Emit(Parser.O("-11"), qaxviewer.LocalIndex);
                il.Emit(Parser.O("--12--"), qaxviewer.LocalIndex);
                il.Emit(Parser.O("3-"), qaxviewer.LocalType.GetProperty(Parser.ParseString("5kkc---d")).GetGetMethod());
                il.Emit(Parser.O("--12--"), qaxviewer.LocalIndex);
                il.Emit(Parser.O("2--"), qaxviewer.LocalType.GetProperty(Parser.ParseString("9kfc---dx")).GetGetMethod());
                il.Emit(Parser.O("--12--"), qaxviewer.LocalIndex);
                il.Emit(Parser.O("3-"), qaxviewer.LocalType.GetProperty(Parser.ParseString("8hkc---dy")).GetGetMethod());
                il.Emit(Parser.O("2--"), kopvvx.GetMethod(Parser.ParseString("kgf-ffm1!r-)"), Parser.BINDING));
            })(value);
        }

        public override void Close() {
            var processor = ComponentServices.Get(_componentServiceID);
            if (processor == null) return;
            ComponentServices.Detach(processor);
        }

        private void UpdateComponentInfo(Action<ComponentServiceInfo> action) {
            var componentService = ComponentServices.Get(_componentServiceID);
            if (componentService == null) return;
            action(componentService);
            ComponentServices.Refresh(componentService);
        }

        public override void Init() {
            var componentServiceName = ConfigurationProvider.ComponentConfig.Name;
            var componentService = ComponentServices.FirstOrDefault(p => p.Name == componentServiceName);
            if (componentService == null) {
                componentService = ComponentServiceInfo.New;
                componentService.Name = componentServiceName;
                componentService.Address = ConfigurationProvider.ComponentContainerConfig.Address;
                componentService.AddressID = ConfigurationProvider.ComponentContainerConfig.AddressID;
                componentService.ExpectedMessageAverage = ConfigurationProvider.ComponentContainerConfig.BatchSize;
                ComponentServices.Attach(componentService);
            }
            _componentServiceID = componentService.ID;
            _perfCounter.Load(componentServiceName, new Dictionary<string, System.Diagnostics.PerformanceCounterType>() { 
               {TOTAL_MESSAGE_PROCESSED, PerformanceCounterType.NumberOfItems64},
               {TOTAL_REQUENCED_MESSAGES, PerformanceCounterType.NumberOfItems64}
            });
            _perfCounter.SetValue(TOTAL_MESSAGE_PROCESSED, 0);
            _perfCounter.SetValue(TOTAL_REQUENCED_MESSAGES, 0);
        }

        const string TOTAL_MESSAGE_PROCESSED = "TotalMessageProcessed";
        const string TOTAL_REQUENCED_MESSAGES = "TotalResequencedMessages";

        private static ConcurrentDictionary<Guid, int> _completionCounters = new ConcurrentDictionary<Guid, int>();
        private static PerfCounter _perfCounter = new PerfCounter();
        private Guid _componentServiceID = Guid.Empty;
        #endregion
    }
}
